package com.idanchuang.component.provider.interceptor;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.idanchuang.component.base.JsonResult;
import com.idanchuang.component.base.exception.common.ErrorCode;
import com.idanchuang.component.base.exception.core.ExDefinition;
import com.idanchuang.component.base.exception.core.ExFactory;
import com.idanchuang.component.logback.helper.LogContext;
import com.idanchuang.component.provider.api.util.RpcThreadLocalUtil;
import com.idanchuang.component.provider.config.RpcConfig;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 权限拦截器
 *
 * @author yjy
 * @date 2019/10/12 16:54
 **/
public class RpcInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(RpcInterceptor.class);

    private RpcConfig rpcConfig;

    public RpcInterceptor(RpcConfig rpcConfig) {
        this.rpcConfig = rpcConfig;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        log.debug("Rpc RequestHeaders > {}", request.getHeaderNames());
        try {
            // 取出header中的ThreadLocal变量表, 存入本地ThreadLocal中
            String mapString = request.getHeader(rpcConfig.getThreadLocalHeaderName());
            if (StringUtils.isNotBlank(mapString)) {
                Map<String, String> map = JSON.parseObject(decodeUrl(mapString), HashMap.class);
                RpcThreadLocalUtil.addToThreadLocal(map);
            }
            return true;
        } catch (Exception e) {
            // 拦截器降级
            LogContext.setKeyword("component-error");
            log.error("RpcInterceptor failed, {}", e.getMessage());
            if (rpcConfig.isPassIfError()) {
                return true;
            }
            return fail(ExFactory.of(ErrorCode.SYSTEM_ERROR, "RPC系统错误"), response);
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                 @Nullable Exception ex) throws Exception {
        // 清空变量表
        RpcThreadLocalUtil.clearThreadLocal();
    }

    /**
     * 处理鉴权失败
     *
     * @param exDefinition 错误信息
     * @param response ..
     * @return ..
     * @throws IOException e
     */
    private boolean fail(ExDefinition exDefinition, HttpServletResponse response) throws IOException {
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        JsonResult result = JsonResult.failure(exDefinition);
        response.getWriter().write(new ObjectMapper().writeValueAsString(result));
        return false;
    }

    private static String decodeUrl(String encodeValue) {
       try {
           return URLDecoder.decode(encodeValue, "UTF-8");
       }catch (Exception e) {
           log.error("decodeUrl failed, encodeValue: {}", encodeValue, e);
       }
       return encodeValue;
    }

}